#ifndef __FACTORY_H__
#define __FACTORY_H__

#include <map>
#include <iostream>
#include <memory>
#include "SingletonHolder.h"

template
<
	class AbstractProduct,
	typename IdentifierType,
	typename ProductCreator = std::shared_ptr<AbstractProduct> (*)()
>
class Factory
{
public:
	template <typename T> friend class SingletonHolder;

	bool Register(const IdentifierType& id, ProductCreator creator)
	{
		return associations_.insert(
			typename AssocMap::value_type(id, creator)).second;
	}

	bool Unregister(const IdentifierType& id)
	{
		return associations_.erase(id) == 1;
	}

	std::shared_ptr<AbstractProduct> CreateObject(const IdentifierType& id) const
	{
		auto i = associations_.find(id);
		if (i == associations_.end()) {
			// handle error ...
			//std::cerr << "Unknown Product ID" << std::endl;
			throw std::runtime_error("Unknown Product ID");
		}
		return (i->second)();
	}

private:
	typedef std::map<IdentifierType, ProductCreator> AssocMap;
	AssocMap associations_;

	//Protection
	Factory() {};
	~Factory() {};
	Factory(const Factory<AbstractProduct, IdentifierType>&) {};
	Factory<AbstractProduct, IdentifierType>& operator=(const Factory<AbstractProduct, IdentifierType>&)
	{
		return *this;
	}
};

void Register();
void UnRegister();

#endif
